﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace Sofire.Data
{
    public partial class QueryEngineBase
    {
        internal MultiNonQueryResult ExecuteTransaction(DbConnection connection, DbTransaction transaction, List<ExecuteCommand> commands, ExecuteCompletedHandler completed, bool autoClosed)
        {
            int value = 0,                      //累计的受影响行数
                executeIndex = 0;               //循环变量，代表每一个执行的 commands，如果引发了异常，executeIndex 则成了引发异常的索引
            DbCommand dbCommand = null;         //每个循环当前的 Command
            Exception exception = null;         //异常，默认为没有异常
            ExecuteCommand command = null;

            bool needAction = completed != null;
            //开始数据库事务
            DbTransaction tran = null;
            ExecuteCommand firstCommand = null;

            var userToken = this.OnExecuting(ExecuteType.Transaction, commands);
            try
            {
                if(connection.State == ConnectionState.Closed)
                    connection.Open();
                tran = transaction ?? connection.BeginTransaction();
                //循环遍历出每一个执行参数 commands
                for( ; executeIndex < commands.Count ; )
                {
                    command = commands[executeIndex];
                    if(command != null)
                    {
                        if(executeIndex == 0)
                        {
                            firstCommand = command;
                            command.Aborted = false;
                        }
                        dbCommand = this.CreateCommand(connection, command);
                        firstCommand.SetRuntimeObject(dbCommand);
                        //设置数据库事务
                        dbCommand.Transaction = tran;
                        value += dbCommand.ExecuteNonQuery();                // 累计受影响行数
                        if(needAction && !completed(executeIndex, command))
                        {
                            throw ExecuteAbortException.Instance;
                        }
                    }
                    executeIndex++;
                }
                tran.Commit();      //提交事务
                executeIndex = -1; //指示操作成功
            }

            catch(Exception ex)
            {
                exception = ex;
                if(tran != null)
                    tran.Rollback();    //回滚
            }
            finally
            {
                if(autoClosed) connection.TryClose();
                tran.TryDispose();
            }

            var r = new MultiNonQueryResult(executeIndex);
            r.Initialization(this, dbCommand, value, exception);

            this.OnExecuted(ExecuteType.Transaction, r, commands, userToken);

            return r;
        }

        internal MultiNonQueryResult ExecuteValues(DbConnection connection, DbTransaction transaction, ExecuteCommand command, object[][] parametersValues, ExecuteCompletedHandler completed, bool autoClosed)
        {
            int value = 0,                      //累计的受影响行数
                executeIndex = 0;               //循环变量，代表每一个执行的 commands，如果引发了异常，executeIndex 则成了引发异常的索引
            DbCommand dbCommand = null;         //每个循环当前的 Command
            Exception exception = null;         //异常，默认为没有异常

            bool needAction = completed != null;
            //开始数据库事务
            DbTransaction tran = null;

            var userToken = this.OnExecuting(ExecuteType.Values, command);
            try
            {
                if(connection.State == ConnectionState.Closed)
                    connection.Open();
                tran = transaction ?? connection.BeginTransaction();

                dbCommand = this.CreateCommand(connection, command);
                dbCommand.Transaction = tran;
                command.SetRuntimeObject(dbCommand);
                foreach(var values in parametersValues)
                {
                    for(int i = 0 ; i < values.Length ; i++)
                    {
                        dbCommand.Parameters[i].Value = values[i];
                    }
                    value += dbCommand.ExecuteNonQuery();                // 累计受影响行数
                    if(needAction && !completed(executeIndex, command))
                    {
                        throw ExecuteAbortException.Instance;
                    }
                    executeIndex++;
                }

                tran.Commit();      //提交事务
                executeIndex = -1; //指示操作成功
            }

            catch(Exception ex)
            {
                exception = ex;
                if(tran != null) tran.Rollback();    //回滚
            }
            finally
            {
                if(autoClosed) connection.TryClose();
                tran.TryDispose();
            }

            var r = new MultiNonQueryResult(executeIndex);
            r.Initialization(this, dbCommand, value, exception);

            this.OnExecuted(ExecuteType.Values, r, command, userToken);

            return r;
        }

        /// <summary>
        /// 执行查询，并完成一个事务。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        /// <param name="completed">每当一个 <see cref="Sofire.Data.ExecuteCommand"/> 执行成功后，将会执行该方法。</param>
        public MultiNonQueryResult ExecuteTransaction(List<ExecuteCommand> commands, ExecuteCompletedHandler completed)
        {
            return this.ExecuteTransaction(this.CreateConnection(), null, commands, completed, true);
        }

        /// <summary>
        /// 执行查询，并完成一个事务。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        public MultiNonQueryResult ExecuteTransaction(List<ExecuteCommand> commands)
        {
            return this.ExecuteTransaction(commands, null);
        }

        /// <summary>
        /// 执行查询，并完成一个事务。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        public MultiNonQueryResult ExecuteTransaction(params ExecuteCommand[] commands)
        {
            return this.ExecuteTransaction(new List<ExecuteCommand>(commands), null);
        }

        /// <summary>
        /// 执行查询，重复填充参数值，并完成一个事务。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        /// <param name="parametersValues">参数值集合。</param>
        public MultiNonQueryResult ExecuteValues(ExecuteCommand command, object[][] parametersValues)
        {
            return this.ExecuteValues(command, parametersValues, null);
        }

        /// <summary>
        /// 执行查询，重复填充参数值，并完成一个事务。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        /// <param name="parametersValues">参数值集合。</param>
        /// <param name="completed">每当填充一个参数值并执行成功后，将会执行该方法。</param>
        public MultiNonQueryResult ExecuteValues(ExecuteCommand command, object[][] parametersValues, ExecuteCompletedHandler completed)
        {
            return this.ExecuteValues(this.CreateConnection(), null, command, parametersValues, completed, true);
        }
    }


    public partial class QueryContext
    {
        /// <summary>
        /// 执行查询，并完成一个事务。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        /// <param name="completed">每当一个 <see cref="Sofire.Data.ExecuteCommand"/> 执行成功后，将会执行该方法。</param>
        public MultiNonQueryResult ExecuteTransaction(List<ExecuteCommand> commands, ExecuteCompletedHandler completed)
        {
            return this.Engine.ExecuteTransaction(this.Connection, this.Transaction, commands, completed, false);
        }

        /// <summary>
        /// 执行查询，并完成一个事务。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        public MultiNonQueryResult ExecuteTransaction(List<ExecuteCommand> commands)
        {
            return this.ExecuteTransaction(commands, null);
        }

        /// <summary>
        /// 执行查询，并完成一个事务。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        public MultiNonQueryResult ExecuteTransaction(params ExecuteCommand[] commands)
        {
            return this.ExecuteTransaction(new List<ExecuteCommand>(commands), null);
        }

        /// <summary>
        /// 执行查询，重复填充参数值，并完成一个事务。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        /// <param name="parametersValues">参数值集合。</param>
        public MultiNonQueryResult ExecuteValues(ExecuteCommand command, object[][] parametersValues)
        {
            return this.ExecuteValues(command, parametersValues, null);
        }

        /// <summary>
        /// 执行查询，重复填充参数值，并完成一个事务。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        /// <param name="parametersValues">参数值集合。</param>
        /// <param name="completed">每当填充一个参数值并执行成功后，将会执行该方法。</param>
        public MultiNonQueryResult ExecuteValues(ExecuteCommand command, object[][] parametersValues, ExecuteCompletedHandler completed)
        {
            return this.Engine.ExecuteValues(this.Connection, this.Transaction, command, parametersValues, completed, false);
        }
    }
}